package com.youngjun.common.security.access;

import com.youngjun.common.security.constant.SecurityConfigConstant;
import com.youngjun.common.security.service.RequestMapService;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import static org.springframework.security.access.SecurityConfig.createList;

public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private RequestMapService requestMapService;

    private boolean strictEnabled=false;

    public CustomFilterInvocationSecurityMetadataSource(RequestMapService requestMapService,boolean strictEnabled) {
        this.requestMapService = requestMapService;
        this.strictEnabled = strictEnabled;
        Assert.notNull(requestMapService, "requestMapService cannot be null");
    }


    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = null;
        if(strictEnabled){
            requestMap = this.requestMapService.getRequestMap(request.getServletPath(), request.getMethod());
        }
        if(requestMap==null){
            requestMap = new LinkedHashMap<>();
        }
        requestMap.put(new AntPathRequestMatcher("/login", HttpMethod.POST.name()), SecurityConfig.createList(SecurityConfigConstant.PERMIT_ALL));
        requestMap.put(new AntPathRequestMatcher("/captcha", HttpMethod.GET.name()), createList(SecurityConfigConstant.PERMIT_ALL));
        requestMap.put(new AntPathRequestMatcher("/rsa/publicKey", HttpMethod.GET.name()), createList(SecurityConfigConstant.PERMIT_ALL));
        requestMap.put(new AntPathRequestMatcher("/oauth/**", null), createList(SecurityConfigConstant.PERMIT_ALL));
        requestMap.put(new AntPathRequestMatcher("/me/**", null), createList(SecurityConfigConstant.AUTHENTICATED));
        if(strictEnabled){
            //default denyAll
            requestMap.put(new AntPathRequestMatcher("/**", null), createList(SecurityConfigConstant.DENY_ALL));
        }else{
            //default authenticated
            requestMap.put(new AntPathRequestMatcher("/**", null), createList(SecurityConfigConstant.AUTHENTICATED));
        }
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
            if (entry.getKey().matches(request)) {
                return entry.getValue();
            }
        }
        if(strictEnabled){
            //default denyAll
            return createList(SecurityConfigConstant.DENY_ALL);
        }else{
            //default authenticated
            return createList(SecurityConfigConstant.AUTHENTICATED);
        }
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }
}
